/**
 * 
 */
package com.tcl.wip.client.spring.config;

import java.util.List;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.ClassUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;

import com.tcl.wip.client.WipApp;
import com.tcl.wip.client.repository.WipRepositoryFactory;


/**
 * @author zhaowen.zhuang
 * @Date Jan 20, 2015
 */
public class WipAppBeanDefinitionParser implements BeanDefinitionParser {

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        String appId = element.getAttribute("app-id");
        String appKey = element.getAttribute("app-Key");
        String server = element.getAttribute("server");
        WipApp app = new WipApp(appId, appKey, server);
        String factoryBeanName = appId + "WipRepositoryFactory";

        registerRepositoryFactory(parserContext, factoryBeanName);

        List<Element> repositoryElemenets = DomUtils.getChildElementsByTagName(element, "repository");
        for (Element repoEle : repositoryElemenets) {
            registerRepository(parserContext, app, factoryBeanName, repoEle);
        }
        return null;
    }

    /**
     * @param parserContext
     * @param app
     * @param factoryBeanName
     * @param repoEle
     */
    private void registerRepository(ParserContext parserContext, WipApp app,
            String factoryBeanName, Element repoEle) {
        String className = repoEle.getAttribute("class");
        RootBeanDefinition definition = new RootBeanDefinition();
        definition.setFactoryBeanName(factoryBeanName);
        definition.setFactoryMethodName("createRepository");
        ConstructorArgumentValues argumentes = new ConstructorArgumentValues();
        try {
            argumentes.addIndexedArgumentValue(0,
                    ClassUtils.forName(className, this.getClass().getClassLoader()));
        } catch (ClassNotFoundException | LinkageError e) {
            throw new IllegalArgumentException("error create repository bean with class = "
                    + className, e);
        }
        argumentes.addIndexedArgumentValue(1, app);
        definition.setConstructorArgumentValues(argumentes);
        BeanDefinitionReaderUtils.registerBeanDefinition(new BeanDefinitionHolder(definition,
                className.substring(className.lastIndexOf(".") + 1)), parserContext.getRegistry());
    }

    /**
     * @param parserContext
     * @param factoryBeanName
     */
    private void registerRepositoryFactory(ParserContext parserContext, String factoryBeanName) {
        RootBeanDefinition factoryBeanDefinition =
                new RootBeanDefinition(WipRepositoryFactory.class);

        BeanDefinitionHolder factoryHolder =
                new BeanDefinitionHolder(factoryBeanDefinition, factoryBeanName);

        BeanDefinitionReaderUtils
                .registerBeanDefinition(factoryHolder, parserContext.getRegistry());
    }


}
